package org.training.apr.model;

import org.training.apr.model.visitor.FamilyVisitor;

@SuppressWarnings("serial")
public class PaymentOrder extends Model {
	private Enterprise enterprise;
	private double rawValue;
	private Vat vat;
	private boolean authorized;
	private boolean supervised;
	private double payedValue;
	
	public Enterprise getEnterprise() {
		return enterprise;
	}
	
	public void setEnterprise(Enterprise enterprise) {
		this.enterprise = enterprise;
	}
	
	public double getRawValue() {
		return rawValue;
	}
	
	public void setRawValue(double rawValue) {
		this.rawValue = rawValue;
	}
	
	public Vat getVat() {
		return vat;
	}
	
	public void setVat(Vat vat) {
		this.vat = vat;
	}
	
	public boolean isAuthorized() {
		return authorized;
	}
	
	private boolean isEnterpriseInFamily(Enterprise hostEnterprise) {
		FamilyVisitor visitor = new FamilyVisitor(hostEnterprise);
		visitor.visit(getEnterprise().getElder());
		
		return visitor.isFamily();
	}

	public boolean isSupervised() {
		return supervised;
	}
	
	/** only for internal processing or data injection by ORM*/
	private void setSupervised(boolean supervised) throws OperationNotAuthorizedException {
		this.supervised = supervised;
	}
	
	public double getValue() {
		if(vat == null) {
			throw new RuntimeException("vat can't be null for this operation");
		}
		return rawValue * (1 + vat.getRelativeTax());
	}

	public double getPayedValue() {
		return payedValue;
	}

	public void markAsSupervised(User author, boolean supervised) throws OperationNotAuthorizedException {
		if(author.getRole().getType().equals(Role.FINANCIAL_DIRECTOR)) {
			setSupervised(supervised);
		} else {
			throw new OperationNotAuthorizedException("No permisions for this operation");
		}
	}

	public boolean isSupervisionRequired(Enterprise hostEnterprise, double supervisionThreshold) {
		return !isEnterpriseInFamily(hostEnterprise) && getValue() > supervisionThreshold;
	}

	public void authorize(Enterprise hostEnterprise, double supervisionThreshold, boolean authorized) throws SupervisionRequiredException {
		if(authorized && !isSupervised() && isSupervisionRequired(hostEnterprise, supervisionThreshold)) {
			throw new SupervisionRequiredException("Requires Supervision");
		}
		this.authorized = authorized;
	}
}
